package core;

//
//GifSequenceWriter.java
//
//Created by Elliot Kroo on 2009-04-25.
//
//This work is licensed under the Creative Commons Attribution 3.0 Unported
//License. To view a copy of this license, visit
//http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative
//Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.


//taken from http://elliot.kroo.net/software/java/GifSequenceWriter/

import javax.imageio.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import java.awt.image.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

public class GifSequenceWriter {
protected ImageWriter gifWriter;
protected ImageWriteParam imageWriteParam;
protected IIOMetadata imageMetaData;

/**
* Creates a new GifSequenceWriter
* 
* @param outputStream the ImageOutputStream to be written to
* @param imageType one of the imageTypes specified in BufferedImage
* @param timeBetweenFramesMS the time between frames in miliseconds
* @param loopContinuously wether the gif should loop repeatedly
* @throws IIOException if no gif ImageWriters are found
*
* @author Elliot Kroo (elliot[at]kroo[dot]net)
*/
public GifSequenceWriter(
  ImageOutputStream outputStream,
  int imageType,
  int timeBetweenFramesMS,
  boolean loopContinuously) throws IIOException, IOException {
// my method to create a writer
gifWriter = getWriter(); 
imageWriteParam = gifWriter.getDefaultWriteParam();
ImageTypeSpecifier imageTypeSpecifier =
  ImageTypeSpecifier.createFromBufferedImageType(imageType);

imageMetaData =
  gifWriter.getDefaultImageMetadata(imageTypeSpecifier,
  imageWriteParam);

String metaFormatName = imageMetaData.getNativeMetadataFormatName();

IIOMetadataNode root = (IIOMetadataNode)
  imageMetaData.getAsTree(metaFormatName);

IIOMetadataNode graphicsControlExtensionNode = getNode(
  root,
  "GraphicControlExtension");

graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute(
  "transparentColorFlag",
  "FALSE");
graphicsControlExtensionNode.setAttribute(
  "delayTime",
  Integer.toString(timeBetweenFramesMS / 10));
graphicsControlExtensionNode.setAttribute(
  "transparentColorIndex",
  "0");

IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
commentsNode.setAttribute("CommentExtension", "Created by MAH");

IIOMetadataNode appEntensionsNode = getNode(
  root,
  "ApplicationExtensions");

IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");

child.setAttribute("applicationID", "NETSCAPE");
child.setAttribute("authenticationCode", "2.0");

int loop = loopContinuously ? 0 : 1;

child.setUserObject(new byte[]{ 0x1, (byte) (loop & 0xFF), (byte)
  ((loop >> 8) & 0xFF)});
appEntensionsNode.appendChild(child);

imageMetaData.setFromTree(metaFormatName, root);

gifWriter.setOutput(outputStream);

gifWriter.prepareWriteSequence(null);
}

public void writeToSequence(RenderedImage img) throws IOException {
gifWriter.writeToSequence(
  new IIOImage(
    img,
    null,
    imageMetaData),
  imageWriteParam);
}

/**
* Close this GifSequenceWriter object. This does not close the underlying
* stream, just finishes off the GIF.
*/
public void close() throws IOException {
gifWriter.endWriteSequence();    
}

/**
* Returns the first available GIF ImageWriter using 
* ImageIO.getImageWritersBySuffix("gif").
* 
* @return a GIF ImageWriter object
* @throws IIOException if no GIF image writers are returned
*/
private static ImageWriter getWriter() throws IIOException {
Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("gif");
if(!iter.hasNext()) {
  throw new IIOException("No GIF Image Writers Exist");
} else {
  return iter.next();
}
}

/**
* Returns an existing child node, or creates and returns a new child node (if 
* the requested node does not exist).
* 
* @param rootNode the <tt>IIOMetadataNode</tt> to search for the child node.
* @param nodeName the name of the child node.
* 
* @return the child node, if found or a new node created with the given name.
*/
private static IIOMetadataNode getNode(
  IIOMetadataNode rootNode,
  String nodeName) {
int nNodes = rootNode.getLength();
for (int i = 0; i < nNodes; i++) {
  if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName)
      == 0) {
    return((IIOMetadataNode) rootNode.item(i));
  }
}
IIOMetadataNode node = new IIOMetadataNode(nodeName);
rootNode.appendChild(node);
return(node);
}

/**
public GifSequenceWriter(
   BufferedOutputStream outputStream,
   int imageType,
   int timeBetweenFramesMS,
   boolean loopContinuously) {

*/


private static ArrayList<File> getSortedFiles (String path)
{
	File folder = new File(path);
	 File[] listOfFiles = folder.listFiles();
	 ArrayList<File> pictureFiles = new ArrayList<File>();
	 
	     for (int i = 0; i < listOfFiles.length; i++) {
	       if (listOfFiles[i].isFile()) {
	    	   String[] tokens = listOfFiles[i].toString().split("\\.(?=[^\\.]+$)");
	    	   if (tokens[1].equals("png") || tokens[1].equals("bmp"))
	    		   pictureFiles.add(listOfFiles[i]);
	       } 
	     }
	     
	    Collections.sort(pictureFiles, 
	    	new Comparator<File>() {
	    	  public int compare(File f1, File f2) {
	    		  return f1.getName().compareTo(f2.getName());
	    	  }
	    	}
	    );
	    return pictureFiles;
}

	public static void createGif (ArrayList<File> sortedFiles, String outputGif, int FPS) throws Exception {
		
		if (sortedFiles.size() > 1) {
		  // grab the output image type from the first image in the sequence
		  BufferedImage firstImage = ImageIO.read(sortedFiles.get(0));
		
		  // create a new BufferedOutputStream with the last argument
		  ImageOutputStream output = 
		    new FileImageOutputStream(new File(outputGif));
		  
		  // create a gif sequence with the type of the first image, 1 second
		  // between frames, which loops continuously
		  GifSequenceWriter writer = 
		    new GifSequenceWriter(output, firstImage.getType(), (1000 / FPS), true);
		  
		  // write out the first image to our sequence...
		  writer.writeToSequence(firstImage);
		  for(int i=1; i<sortedFiles.size(); i++) {
		    BufferedImage nextImage = ImageIO.read(sortedFiles.get(i));
		    writer.writeToSequence(nextImage);
		  }
		  
		  writer.close();
		  output.close();
		} else {
			throw new IllegalArgumentException();
		}
	}

	public static void createGif (String inputDir, String outputGif, int FPS) throws Exception {
		createGif (getSortedFiles(inputDir), outputGif, FPS);
	}
}